/*************************************************************************
 *                                                                       *
 * This file is part of the FreeMAPs distribution.  For full copyright   *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:           sqbang                                              *
 * Email:            sqbang@ustc.edu                                     *
 * Date:             2011.09.08                                          *
 *                                                                       *
 *************************************************************************/

//declaration header
#include "COMMON/info/TimePatch.h"

//COMMON headers
#include "COMMON/base/DefaultParameters.h"
#include "COMMON/info/InfoManager.h"
//#include "COMMON/info/TimeInfo.h"
#include "COMMON/tbox/LogMessage.h"

namespace FreeMAPs
{

TimePatch::TimePatch(
    const std::string& parent_name,
    const std::string& patch_name,
    const bool is_global):
    Parent                      (parent_name, patch_name),
    d_is_global                 (is_global),
    d_start_time                (0.0),
    d_end_time                  (1.0),
    d_fixed_dt                  (0.1),
    d_max_dt                    (d_start_time),
    d_cfl_number                (1.),
    d_time_accuracy_order (1),
    d_is_current_time_in_range  (false)
{}



void
TimePatch::clear()
{
    /*
     * do nothing
     */
}



bool
TimePatch::check_all_info_db (
        const InputDatabase* db)
{
    //start_time
    if( !db->key_exists("start_time") )
    {
        FREEMAPS_ERROR("in \"time_info\", can not find  \"start_time\" \n");
        return false;
    }
    if( !db->is_double("start_time") )
    {
        FREEMAPS_ERROR("in \"time_info\", \"start_time\" should be double \n");
        return false;
    }

    //end_time
    if( !db->key_exists("end_time") )
    {
        FREEMAPS_ERROR("in \"time_info\", can not find  \"end_time\" \n");
        return false;
    }
    if( !db->is_double("end_time") )
    {
        FREEMAPS_ERROR("in \"time_info\", \"end_time\" should be double \n");
        return false;
    }

    //dt
    if( !db->key_exists("dt") )
    {
        FREEMAPS_ERROR("in \"time_info\", can not find  \"dt\" \n");
        return false;
    }
    if( !db->is_double("dt") )
    {
        FREEMAPS_ERROR("in \"time_info\", \"dt\" should be double \n");
        return false;
    }

    return true;
}



void
TimePatch::get_from_input (
        const InputDatabase* db)
{
    this->prepare_for_use (db);

    db->insert_allowable_key ("start_time");
    db->insert_allowable_key ("end_time");
    db->insert_allowable_key ("dt");
    db->insert_allowable_key ("max_dt");
    db->insert_allowable_key ("time_increment_controller");
    db->insert_allowable_key ("auto_controller_parameters");
    db->insert_allowable_key ("cfl_number");
    db->insert_allowable_key ("time_accuracy_order");
    db->check_allowable_keys ();

    /*
     * build start_time and end_time
     */
    {

        //don't need start time now
        if (db->key_exists ("start_time") && db->is_double("start_time"))
        {
            db->check_optional_key ("start_time", DataType::DOUBLE, false, false);//start_time==0
            d_start_time = db->get_double_with_default ("start_time", d_start_time);
        }

        if (db->key_exists ("end_time") && db->is_double("end_time"))
        {
            db->check_optional_key ("end_time",   DataType::DOUBLE, false, false);
            d_end_time   = db->get_double_with_default ("end_time",   d_end_time);
        }

        if (d_start_time > d_end_time)
        {
            std::ostringstream os;
            os << "\"start_time\" = " << d_start_time << '\n';
            os << "it should less than \"end_time\" = " << d_end_time << '\n';
            LogMessage::unknown_error(
                db,
                os.str());
        }
    }
    /*
     * build dt and max_dt
     */
    {
        if (db->key_exists ("dt") && db->is_double("dt"))
        {
            db->check_optional_key ("dt", DataType::DOUBLE, true, false);
            db->check_allowable_double_value ("dt", 0., MathUtilities<double>::get_max());
            const double dt = db->get_double_with_default ("dt", this->get_fixed_dt());
            this->set_fixed_dt (dt);
        }
        if(this->get_fixed_dt() < 0)
        {
            this->set_fixed_dt (0.1);
        }
    }
}



std::ostream&
operator << (
    std::ostream& os,
    const TimePatch& rhs)
{
    os << "time_info" << RTN_FLAG << "{" << RTN_FLAG;

    const int max_width = static_cast<int>(std::string ("time_increment_controller").size());

    os << LogMessage::get_equal_width_string ("start_time", ONE_TAB, max_width) << " = " << rhs.d_start_time  << RTN_FLAG;
    os << LogMessage::get_equal_width_string ("end_time",   ONE_TAB, max_width) << " = " << rhs.d_end_time  << RTN_FLAG;
    os << LogMessage::get_equal_width_string ("dt",         ONE_TAB, max_width) << " = " << rhs.d_fixed_dt  << RTN_FLAG;

    os << "}";

    return os;
}

}

